package com.youlin.security;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.youlin.entities.BygMenu;
import com.youlin.entities.BygRoleMenu;
import com.youlin.entities.BygRole;
import com.youlin.service.BygMenuService;
import com.youlin.service.BygRoleMenuService;
import com.youlin.service.BygRoleService;
import com.youlin.untils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Component
public class MyMetadataSource implements FilterInvocationSecurityMetadataSource {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    BygMenuService bygMenuService;
    @Autowired
    BygRoleMenuService bygRoleMenuService;
    @Autowired
    BygRoleService bygRoleService;

    @Override
    public Collection<ConfigAttribute> getAttributes(Object obj) {
        String requestUrl = ((FilterInvocation) obj).getRequestUrl();
        List<BygMenu> allMenus = RedisUtil.getList(redisTemplate, "security:allMenus", BygMenu.class);
        if (allMenus == null || allMenus.size() == 0) {
            allMenus = bygMenuService.list(new QueryWrapper<>());
            if (allMenus.size() > 0) RedisUtil.setObject(redisTemplate, "security:allMenus", allMenus);
        }
        Optional<BygMenu> menuOptional = allMenus.parallelStream().filter(menu ->
                new AntPathMatcher().match(menu.getPath(), requestUrl)).findFirst();
        if (menuOptional.isPresent()) {
            Integer menuId = menuOptional.get().getId();
            List<String> roleNames = RedisUtil.getList(redisTemplate, "security:menuIds:" + menuId, String.class);
            if (roleNames == null || roleNames.size() == 0) {
                List<Integer> roleIds = bygRoleMenuService.list(new QueryWrapper<BygRoleMenu>()
                        .eq("menu_id", menuId))
                        .parallelStream().map(BygRoleMenu::getRoleId).collect(Collectors.toList());
                roleNames = bygRoleService.listByIds(roleIds)
                        .parallelStream().map(BygRole::getName).collect(Collectors.toList());
                if (roleNames.size() > 0) RedisUtil.setObject(redisTemplate, "security:menuIds:" + menuId, roleNames);
            }
            String[] roleArr = new String[roleNames.size()];
            return SecurityConfig.createList(roleNames.toArray(roleArr));
        }
        //没有匹配上的资源，都是登录访问
        throw new AccessDeniedException("权限不足");
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return FilterInvocation.class.isAssignableFrom(aClass);
    }

}
